﻿
#undef USE_ASSEMBLY_GUID

namespace TestApplication
{
    #region Namespaces
    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Threading.Tasks;
    using System.Windows;
    using Custom.Windows;

    #endregion

    /// <summary>
    ///     Interaction logic for App.xaml
    /// </summary>
    public partial class App
    {
        /// <summary>
        ///     Initializes a new instance of the <see cref="App" /> class.
        /// </summary>
        /// <exception cref="System.InvalidOperationException">
        ///     More than one instance of the
        ///     <see cref="System.Windows.Application" /> class is created per <see cref="System.AppDomain" />.
        /// </exception>
        public App()
                : base(ApplicationInstanceAwareness.Host)
        {
            //NOTE: Change the awareness in the default constructor to switch from global awareness and local awareness!
        }

        //This function is evaluated even if the GuidAttribute is defined for the assembly.
        //The compile switch is used to change the metohd used to define the application identifier.
#if !USE_ASSEMBLY_GUID
        /// <summary>
        ///     Called when the the application identifier has to be generated.
        /// </summary>
        /// <returns>
        ///     The string used to identify the application univocally.
        /// </returns>
        /// <remarks>
        ///     <para>
        ///         The base implementation produces a <see langword="null" /> value; in such a case, if the entry assembly is
        ///         decorated with a <see cref="System.Runtime.InteropServices.GuidAttribute" />, that value will be used as an
        ///         application identifier.
        ///     </para>
        ///     <para>
        ///         Note that the method should return a <c>constant</c> value, since it is used
        ///         to mark univocally the application.
        ///         <para>
        ///             The encouraged approach to mark an application univocally, is marking the entry assembly with a proper
        ///             <see cref="System.Runtime.InteropServices.GuidAttribute" />; this method should be used only if such a
        ///             method
        ///             is impractical or not possible.
        ///         </para>
        ///     </para>
        /// </remarks>
        protected override string GenerateApplicationId()
        {
            return "A2048947-1DBF-492b-AADF-3DCFC8B24801";
        }
#endif

        /// <summary>
        ///     Raises the <see cref="Application.Startup" /> event.
        /// </summary>
        /// <param name="e">The <see cref="System.Windows.StartupEventArgs" /> instance containing the event data.</param>
        /// <param name="isFirstInstance">If set to <c>true</c> the current instance is the first application instance.</param>
        protected override async void OnStartup(StartupEventArgs e, bool? isFirstInstance)
        {
            base.OnStartup(e, isFirstInstance);

            switch (isFirstInstance)
            {
                case false:
                {
                    var window = MainWindow;
                    const string message = "I am not the first application, and I'm going to shutdown!";
                    const string title = "TestApplication - Next instance";
                    if (window != null)
                        MessageBox.Show(window, message, title);
                    else
                        MessageBox.Show(message, title);

                    Shutdown(1);
                    break;
                }
                case true:
                {
                    var arg = e.Args.FirstOrDefault() ?? string.Empty;
                    int seconds;
                    if (arg.StartsWith("relinquish=") && int.TryParse(arg.Substring(11), out seconds))
                    {
                        await TaskEx.Delay(TimeSpan.FromSeconds(seconds));
                        RelinquishSynchronizationObjects();
                    }
                    break;
                }
                default:
                {
                    var window = MainWindow;
                    const string message = "Unable to determine if another instance is present already.";
                    const string title = "TestApplication - Unknown instance";
                    if (window != null)
                        MessageBox.Show(window, message, title);
                    else
                        MessageBox.Show(message, title);
                    break;
                }
            }
        }

        protected override void OnIsFirstInstanceChanged(bool? oldValue, bool? newValue)
        {
            base.OnIsFirstInstanceChanged(oldValue, newValue);

            if (oldValue.HasValue)
            {
                const string title = "TestApplication";
                var window = MainWindow;
                var message = string.Format("IsFirstInstance value changed to '{0}'.", newValue != null ? newValue.ToString() : "<null>");
                if (window != null)
                    MessageBox.Show(window, message, title);
                else
                    MessageBox.Show(message, title);
            }
        }

        /// <summary>
        ///     Raises the <see cref="Custom.Windows.InstanceAwareApplication.StartupNextInstance" /> event.
        /// </summary>
        /// <param name="e">The <see cref="Custom.Windows.StartupNextInstanceEventArgs" /> instance containing the event data.</param>
        protected override void OnStartupNextInstance(StartupNextInstanceEventArgs e)
        {
            base.OnStartupNextInstance(e);

            var window = MainWindow;
            var message = "Another instance of this application was started";
            const string title = "TestApplication - First instance";
            if (e.Args.Length > 0)
                message += string.Format("\nargs:\n{0}", EnumerableToString(e.Args));

            if (window != null)
                MessageBox.Show(window, message, title);
            else
                MessageBox.Show(message, title);
        }

        /// <summary>
        ///     Converts an enumerable in a string.
        /// </summary>
        /// <param name="enumerable">The enumerable.</param>
        /// <returns>The string containing the enumerable items.</returns>
        private static string EnumerableToString<T>(IEnumerable<T> enumerable)
        {
            return enumerable.Cast<object>()
                             .Where(obj => obj != null)
                             .Aggregate(string.Empty, (current, obj) => string.Format("{0}{1}\n", current, obj));
        }
    }
}